package views;

import java.util.List;
import java.util.ListIterator;

import javaroadeditor.Activator;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseWheelListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.part.ViewPart;

import control.ComponentProvider;
import control.ImageCreator;
import core.Coordinate;
import factory.ComponentInterface;
import factory.components.Earth;
import factory.components.Water;

/**
 * 
 * @author albertcsani & fsanyi89
 * 
 */
public class RoadEditorView extends ViewPart {
	public static final String ID = "JavaRoadEditor.roadEditorView";
	private int zoomFactor = 3;
	private static final int defaultWater = 50;
	private static final Point mapSize = new Point(500, 300);
	private Label titleLabel2;
	private ScrolledComposite scrollBox;
	private Composite mParent;
	private Point fromPoint = null, toPoint = new Point(10, 10);
	private ComponentProvider cp;
	private IActionBars bars;

	private Image img = Activator.getImageDescriptor("icons/alt_window_32.gif").createImage();
	private Image imgQC = Activator.getImageDescriptor("icons/CQuaryCrane.png").createImage();
	private Image imgB = Activator.getImageDescriptor("icons/CBuilding.png").createImage();
	private Image imgG = Activator.getImageDescriptor("icons/CGate.png").createImage();
	private Image imgTT = Activator.getImageDescriptor("icons/CTerminalTruck.png").createImage();
	private Image imgRT = Activator.getImageDescriptor("icons/CRoadTruck.png").createImage();
	private Image imgRS = Activator.getImageDescriptor("icons/CReachStacker.png").createImage();
	private Image imgST = Activator.getImageDescriptor("icons/Building.png").createImage();
	private Image imgV = Activator.getImageDescriptor("icons/CVessel.png").createImage();

	/**
	 * Alapertelmezett konstruktor
	 */
	public RoadEditorView() {
	}

	/**
	 * a View-nak a letrehozasa
	 */
	public void createPartControl(final Composite parent) {
		parent.setLayout(new FillLayout());
		scrollBox = new ScrolledComposite(parent, SWT.V_SCROLL | SWT.H_SCROLL);

		mParent = new Composite(scrollBox, SWT.DOUBLE_BUFFERED);
		cp = ComponentProvider.INSTANCE;
		cp.setComposite(mParent);

		scrollBox.setContent(mParent);
		mParent.setLayout(null);

		titleLabel2 = new Label(mParent, SWT.NONE);
		titleLabel2.setBounds(mapSize.x * zoomFactor, mapSize.y * zoomFactor, 1, 1);
		titleLabel2.setText(" ");
		titleLabel2.setBackground(new Color(mParent.getDisplay(), 100, 200, 100));
		mParent.setSize(mParent.computeSize(SWT.DEFAULT, SWT.DEFAULT, true));

		// egy kezdo felulet letrehozasa
		Water water = new Water(new Coordinate(((int) mParent.getBounds().width / zoomFactor) - defaultWater, 0), new Coordinate(defaultWater, ((int) mParent.getBounds().height / zoomFactor)));
		Earth earth = new Earth(new Coordinate(0, 0), new Coordinate(((int) mParent.getBounds().width / zoomFactor) - defaultWater, ((int) mParent.getBounds().height / zoomFactor)));
		cp.addComponent(water);
		cp.addComponent(earth);

		bars = getViewSite().getActionBars();

		/**
		 * az ujrarajzolo Listener
		 */
		mParent.addListener(SWT.Paint, new Listener() {
			public void handleEvent(Event e) {
				cp.redrawProperties();
				// itt kell vegigmenni az osszes komponensen a mit ki kell
				// rajzolni.....
				GC gc = e.gc;
				List<ComponentInterface> components = cp.getComponents();
				ListIterator<ComponentInterface> li = components.listIterator();
				while (li.hasNext()) {
					ComponentInterface component = li.next();
					// acim mikor mit rajzoljon ki......
					String compName = component.getClass().getSimpleName();
					if (compName.equals("Water")) {
						gc.setBackground(new Color(parent.getDisplay(), 0, 0, 140));
						gc.fillRectangle(component.getPosition().getX() * zoomFactor, component.getPosition().getY() * zoomFactor, component.getSize().getX() * zoomFactor, component.getSize().getY()
								* zoomFactor);
					} else if (compName.equals("Earth")) {
						gc.setBackground(new Color(parent.getDisplay(), 92, 145, 63));
						gc.fillRectangle(component.getPosition().getX() * zoomFactor, component.getPosition().getY() * zoomFactor, component.getSize().getX() * zoomFactor, component.getSize().getY()
								* zoomFactor);
					} else if (compName.equals("Terminal")) {
						gc.setBackground(new Color(parent.getDisplay(), 200, 200, 200));
						gc.fillRectangle(component.getPosition().getX() * zoomFactor, component.getPosition().getY() * zoomFactor, component.getSize().getX() * zoomFactor, component.getSize().getY()
								* zoomFactor);
					} else if (compName.equals("Stack")) {
						new ImageCreator().CreateStack(gc, parent, component, zoomFactor);
					} else if (compName.equals("RailMountedGantry")) {
						new ImageCreator().CreateRailMountedGantry(gc, parent, component, zoomFactor);
					} else if (compName.equals("RubberTiredGantry")) {
						new ImageCreator().CreateRubberTiredGantry(gc, parent, component, zoomFactor);
					} else {
						try {
							if (compName.equals("QuaryCrane")) {
								img = imgQC;
							} else if (compName.equals("Building")) {
								img = imgB;
							} else if (compName.equals("Gate")) {
								img = imgG;
							} else if (compName.equals("TerminalTruck")) {
								img = imgTT;
							} else if (compName.equals("RoadTruck")) {
								img = imgRT;
							} else if (compName.equals("ReachStacker")) {
								img = imgRS;
							} else if (compName.equals("Stack")) {
								img = imgST;
							} else if (compName.equals("Vessel")) {
								img = imgV;
							}
						} catch (Exception e1) {
						}
						int orientation = component.getOrientation();
						if (orientation != SWT.UP) {
							ImageData imgData = img.getImageData();
							img = new Image(mParent.getDisplay(), rotate(imgData, orientation));

							int x = component.getSize().getX();
							int y = component.getSize().getY();

							if (orientation == SWT.RIGHT || orientation == SWT.LEFT) {
								x = component.getSize().getY();
								y = component.getSize().getX();
							}
							gc.drawImage(img, 0, 0, img.getBounds().width, img.getBounds().height, component.getPosition().getX() * zoomFactor, component.getPosition().getY() * zoomFactor, x
									* zoomFactor, y * zoomFactor);
							img.dispose();
						} else {
							gc.drawImage(img, 0, 0, img.getBounds().width, img.getBounds().height, component.getPosition().getX() * zoomFactor, component.getPosition().getY() * zoomFactor, component
									.getSize().getX() * zoomFactor, component.getSize().getY() * zoomFactor);
						}
					}
				} // while (li.hasNext())
				if (cp.getCompToPlace() != null) {
					boolean isResizable = true;
					String compName = cp.getCompToPlace().getClass().getSimpleName();
					if (compName.equals("TerminalTruck")) {
						img = imgTT;
						isResizable = false;
					} else if (compName.equals("RoadTruck")) {
						img = imgRT;
						isResizable = false;
					} else if (compName.equals("ReachStacker")) {
						img = imgRS;
						isResizable = false;
					} else if (compName.equals("QuaryCrane")) {
						img = imgQC;
						isResizable = false;
					} else if (compName.equals("Vessel")) {
						img = imgV;
						isResizable = false;
					}
					// a nem meretezheto elemek kirajzolasa

					if (!isResizable) {
						ComponentInterface component = cp.getCompToPlace();
						int orientation = component.getOrientation();
						// ha nem felfele nez akkro megforgatjuk akpet
						if (orientation != SWT.UP) {
							ImageData imgData = img.getImageData();
							// imgData = rotate(imgData, orientation);
							img = new Image(mParent.getDisplay(), rotate(imgData, orientation));

							int x = component.getSize().getX();
							int y = component.getSize().getY();

							if (orientation == SWT.RIGHT || orientation == SWT.LEFT) {
								x = component.getSize().getY();
								y = component.getSize().getX();
							}
							gc.drawImage(img, 0, 0, img.getBounds().width, img.getBounds().height, component.getPosition().getX() * zoomFactor, component.getPosition().getY() * zoomFactor, x
									* zoomFactor, y * zoomFactor);
							img.dispose();
						} else { // if (orientation != SWT.UP) {
							gc.drawImage(img, 0, 0, img.getBounds().width, img.getBounds().height, component.getPosition().getX() * zoomFactor, component.getPosition().getY() * zoomFactor, component
									.getSize().getX() * zoomFactor, component.getSize().getY() * zoomFactor);
						}
						// keret szinenek a meghatarozasa
						if (cp.isPlaceble()) {
							gc.setForeground(new Color(parent.getDisplay(), 0, 255, 0));
						} else {
							gc.setForeground(new Color(parent.getDisplay(), 255, 0, 0));
						}

						int x = component.getSize().getX();
						int y = component.getSize().getY();

						if (orientation == SWT.RIGHT || orientation == SWT.LEFT) {
							x = component.getSize().getY();
							y = component.getSize().getX();
						}
						// keret kirajzolasa az elem kore
						gc.drawRectangle(component.getPosition().getX() * zoomFactor, component.getPosition().getY() * zoomFactor, x * zoomFactor, y * zoomFactor);

					} // if !resizable
					if (isResizable) {
						// ComponentInterface component =
						// cp.getComponent();
						if (fromPoint != null) {
							// /
							int fx = fromPoint.x;
							int fy = fromPoint.y;
							int tx = toPoint.x;
							int ty = toPoint.y;

							if (fx > tx) {
								int tmp = fx;
								fx = tx;
								tx = tmp;
							}
							if (fy > ty) {
								int tmp = fy;
								fy = ty;
								ty = tmp;
							}
							tx = tx - fx;
							ty = ty - fy;
							cp.getCompToPlace().setPosition(new Coordinate(fx, fy));
							cp.getCompToPlace().setSize(new Coordinate(tx, ty));
							if (cp.isPlaceble()) {
								gc.setForeground(new Color(parent.getDisplay(), 0, 255, 0));
							} else {
								gc.setForeground(new Color(parent.getDisplay(), 255, 0, 0));
							}
							cp.getCompToPlace().setPosition(new Coordinate(fromPoint.x, fromPoint.y));
							cp.getCompToPlace().setSize(new Coordinate(toPoint.x, toPoint.y));
							gc.drawRectangle(fx * zoomFactor, fy * zoomFactor, tx * zoomFactor, ty * zoomFactor);
						}
					}
				} // if (cp.getCompToPlace() != null) {
				if (cp.getSelected() != null) {
					gc.setForeground(new Color(parent.getDisplay(), 0, 0, 255));
					if (cp.getSelected().getOrientation() == SWT.UP || cp.getSelected().getOrientation() == SWT.DOWN) {
						gc.drawRectangle(cp.getSelected().getPosition().getX() * zoomFactor, cp.getSelected().getPosition().getY() * zoomFactor, cp.getSelected().getSize().getX() * zoomFactor, cp
								.getSelected().getSize().getY()
								* zoomFactor);
					} else {
						gc.drawRectangle(cp.getSelected().getPosition().getX() * zoomFactor, cp.getSelected().getPosition().getY() * zoomFactor, cp.getSelected().getSize().getY() * zoomFactor, cp
								.getSelected().getSize().getX()
								* zoomFactor);
					}
				}
				if (cp.getSelected() != null) {
					ComponentInterface ci = cp.getSelected();
					gc.setForeground(new Color(parent.getDisplay(), 0, 0, 255));
					if (ci.getOrientation() == SWT.UP || ci.getOrientation() == SWT.DOWN) {
						gc.drawRectangle(ci.getPosition().getX() * zoomFactor, ci.getPosition().getY() * zoomFactor, ci.getSize().getX() * zoomFactor, ci.getSize().getY() * zoomFactor);
					} else {
						gc.drawRectangle(ci.getPosition().getX() * zoomFactor, ci.getPosition().getY() * zoomFactor, ci.getSize().getY() * zoomFactor, ci.getSize().getX() * zoomFactor);
					}
				}
			}
		});
		/**
		 * MouseListener az egerkattintasokra
		 */
		mParent.addMouseListener(new MouseListener() {

			public void mouseDoubleClick(MouseEvent e) {

			}

			/**
			 * Ha az eger gomb levan nyomva
			 */
			public void mouseDown(MouseEvent e) {
				if (cp.getCompToPlace() != null) { // csak ha van amit lerakni
					if (e.button == 1) { // ha a bal gomv volt lenyomva akkro
											// bealitja a kezdopontot
						fromPoint = new Point(e.x / zoomFactor, e.y / zoomFactor);
					} else if (e.button == 3) { // ha a bal akkor leelenorizni
												// hogy forgathato-e, ha igen,
												// akkor megforditani
						ComponentInterface comp = cp.getCompToPlace();
						int orientation = comp.getOrientation();
						switch (orientation) {
						case SWT.UP:
							comp.setOrientation(SWT.RIGHT);
							break;
						case SWT.RIGHT:
							comp.setOrientation(SWT.DOWN);
							break;
						case SWT.DOWN:
							comp.setOrientation(SWT.LEFT);
							break;
						case SWT.LEFT:
							comp.setOrientation(SWT.UP);
							break;

						}
						mParent.redraw();
					}
				} else { // ha nincs amit lerakni akkor kivalsztja az elemet
							// amire kattintva volt
					cp.selectComponent(e.x / zoomFactor, e.y / zoomFactor);
					mParent.redraw();
				}

			}

			/**
			 * az eger gomb felemelve
			 */
			public void mouseUp(MouseEvent e) {
				if (cp.getCompToPlace() != null) {
					if (e.button == 1) { // bal gomb
						toPoint = new Point(e.x / zoomFactor, e.y / zoomFactor);
						if (fromPoint.x > toPoint.x) {
							int tmp = fromPoint.x;
							fromPoint.x = toPoint.x;
							toPoint.x = tmp;
						}
						if (fromPoint.y > toPoint.y) {
							int tmp = fromPoint.y;
							fromPoint.y = toPoint.y;
							toPoint.y = tmp;
						}
						toPoint.x = toPoint.x - fromPoint.x;
						toPoint.y = toPoint.y - fromPoint.y;

						cp.getCompToPlace().setPosition(new Coordinate(fromPoint.x, fromPoint.y));
						cp.getCompToPlace().setSize(new Coordinate(toPoint.x, toPoint.y));

						if (cp.isPlaceble()) {
							cp.addComponent();
							cp.getCompToPlace().setPosition(new Coordinate(e.x / zoomFactor, e.y / zoomFactor));
						}
						mParent.redraw();
						fromPoint = null;
					}
				}
			}
		});
		/**
		 * MouseMoveListener az eger mozgatasra
		 */
		mParent.addMouseMoveListener(new org.eclipse.swt.events.MouseMoveListener() {
			public void mouseMove(org.eclipse.swt.events.MouseEvent e) {
				ComponentInterface tempComp = cp.getCompToPlace();
				if (tempComp != null) {
					tempComp.setPosition(new Coordinate((int) e.x / zoomFactor, (int) e.y / zoomFactor));
					toPoint = new Point(e.x / zoomFactor, e.y / zoomFactor);
					mParent.redraw();
				}

				bars.getStatusLineManager().setMessage("x: " + e.x / zoomFactor + "  y: " + e.y / zoomFactor);
			}
		});
		/**
		 * MouseTrackListener hogy ne rajzoljon hujwesegeket amikor kimegy az
		 * eger
		 */
		mParent.addMouseTrackListener(new org.eclipse.swt.events.MouseTrackListener() {

			/**
			 * Amikor az eger belepik az editorba
			 */
			public void mouseEnter(MouseEvent e) {
				mParent.setFocus();
			}

			/**
			 * Amikor az eger kilepik az editorbol
			 */
			public void mouseExit(MouseEvent e) {
				ComponentInterface tempComp = cp.getCompToPlace();
				if (tempComp != null) {
					tempComp.setPosition(new Coordinate(-100, -100));
					mParent.redraw();
					mParent.update();
				}

				bars.getStatusLineManager().setMessage("");
			}

			/**
			 * Az eger stagnal egy helyben...
			 */
			public void mouseHover(MouseEvent e) {
			}
		});
		/**
		 * Lsitener az gorgore (zoom)
		 */
		mParent.addMouseWheelListener(new MouseWheelListener() {
			public void mouseScrolled(MouseEvent e) {
				if (e.stateMask == SWT.CTRL) {

					if (e.count < 0 && zoomFactor > 1) {
						zoomFactor--;
						titleLabel2.setBounds(mapSize.x * zoomFactor, mapSize.y * zoomFactor, 1, 1);
						mParent.setSize(mParent.computeSize(SWT.DEFAULT, SWT.DEFAULT, true));
						mParent.redraw();
					}
					if (e.count > 0 && zoomFactor < 20) {
						zoomFactor++;
						titleLabel2.setBounds(mapSize.x * zoomFactor, mapSize.y * zoomFactor, 1, 1);
						mParent.setSize(mParent.computeSize(SWT.DEFAULT, SWT.DEFAULT, true));
						mParent.redraw();
					}
				}

			}
		});
		/**
		 * Szinten gorgo a windozra
		 */
		mParent.getDisplay().addFilter(SWT.MouseWheel, new Listener() {

			@Override
			public void handleEvent(Event e) {
				if (e.stateMask == SWT.CTRL && e.widget.toString().equals("Shell {Java 2D}")) {

					if (e.count < 0 && zoomFactor > 1) {
						zoomFactor--;
						titleLabel2.setBounds(mapSize.x * zoomFactor, mapSize.y * zoomFactor, 1, 1);
						mParent.setSize(mParent.computeSize(SWT.DEFAULT, SWT.DEFAULT, true));
						mParent.redraw();
					}
					if (e.count > 0 && zoomFactor < 20) {
						zoomFactor++;
						titleLabel2.setBounds(mapSize.x * zoomFactor, mapSize.y * zoomFactor, 1, 1);
						mParent.setSize(mParent.computeSize(SWT.DEFAULT, SWT.DEFAULT, true));
						mParent.redraw();
					}
				}

			}
		});

		mParent.setSize(mParent.computeSize(SWT.DEFAULT, SWT.DEFAULT, true));
	}

	/**
	 * Egy kicsi metodusocska ImageDatak forgatasara
	 * 
	 * @param srcData
	 *            a forgatando ImageData
	 * @param direction
	 *            az irany amibe elkell forditani
	 * @return az elforgatott ImageData
	 */
	static ImageData rotate(ImageData srcData, int direction) {
		int bytesPerPixel = srcData.bytesPerLine / srcData.width;
		int destBytesPerLine = (direction == SWT.DOWN) ? srcData.width * bytesPerPixel : srcData.height * bytesPerPixel;
		byte[] newData = new byte[srcData.data.length];
		int width = 0, height = 0;
		for (int srcY = 0; srcY < srcData.height; srcY++) {
			for (int srcX = 0; srcX < srcData.width; srcX++) {
				int destX = 0, destY = 0, destIndex = 0, srcIndex = 0;
				switch (direction) {
				case SWT.LEFT: // left 90 degrees
					destX = srcY;
					destY = srcData.width - srcX - 1;
					width = srcData.height;
					height = srcData.width;
					break;
				case SWT.RIGHT: // right 90 degrees
					destX = srcData.height - srcY - 1;
					destY = srcX;
					width = srcData.height;
					height = srcData.width;
					break;
				case SWT.DOWN: // 180 degrees
					destX = srcData.width - srcX - 1;
					destY = srcData.height - srcY - 1;
					width = srcData.width;
					height = srcData.height;
					break;
				}
				destIndex = (destY * destBytesPerLine) + (destX * bytesPerPixel);
				srcIndex = (srcY * srcData.bytesPerLine) + (srcX * bytesPerPixel);
				System.arraycopy(srcData.data, srcIndex, newData, destIndex, bytesPerPixel);
			}
		}
		// destBytesPerLine is used as scanlinePad to ensure that no padding is
		// required
		ImageData imgD = new ImageData(width, height, srcData.depth, srcData.palette, destBytesPerLine, newData);
		int whitePixel = imgD.palette.getPixel(new RGB(255, 255, 255));
		imgD.transparentPixel = whitePixel;
		return imgD;
	}

	@Override
	public void setFocus() {
	}
}
